package org.convallaria.infrastruct.rg.loadbalancer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.List;
import java.util.Random;

/**
 * 自定义负载均衡器
 * 提供多种负载均衡策略
 * 
 * @author gjh
 * @since 2025-01-27
 */
@Slf4j
@Component
public class CustomLoadBalancer {
    
    private final LoadBalancerClient loadBalancerClient;
    private final Random random = new Random();
    
    public CustomLoadBalancer(LoadBalancerClient loadBalancerClient) {
        this.loadBalancerClient = loadBalancerClient;
    }
    
    /**
     * 随机负载均衡
     * 
     * @param instances 服务实例列表
     * @return 选中的实例
     */
    public ServiceInstance randomChoose(List<ServiceInstance> instances) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        int index = random.nextInt(instances.size());
        ServiceInstance instance = instances.get(index);
        log.debug("随机选择实例: {}:{}", instance.getHost(), instance.getPort());
        return instance;
    }
    
    /**
     * 轮询负载均衡
     * 
     * @param instances 服务实例列表
     * @param roundRobinIndex 轮询索引（需要外部维护）
     * @return 选中的实例
     */
    public ServiceInstance roundRobinChoose(List<ServiceInstance> instances, int roundRobinIndex) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        int index = roundRobinIndex % instances.size();
        ServiceInstance instance = instances.get(index);
        log.debug("轮询选择实例: {}:{} (index: {})", instance.getHost(), instance.getPort(), index);
        return instance;
    }
    
    /**
     * 权重负载均衡
     * 
     * @param instances 服务实例列表
     * @return 选中的实例
     */
    public ServiceInstance weightedChoose(List<ServiceInstance> instances) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        // 计算总权重
        double totalWeight = instances.stream()
                .mapToDouble(instance -> {
                    String weightStr = instance.getMetadata().get("nacos.weight");
                    return weightStr != null ? Double.parseDouble(weightStr) : 1.0;
                })
                .sum();
        
        if (totalWeight <= 0) {
            return randomChoose(instances);
        }
        
        // 随机选择
        double randomWeight = random.nextDouble() * totalWeight;
        double currentWeight = 0;
        
        for (ServiceInstance instance : instances) {
            String weightStr = instance.getMetadata().get("nacos.weight");
            double weight = weightStr != null ? Double.parseDouble(weightStr) : 1.0;
            currentWeight += weight;
            
            if (randomWeight <= currentWeight) {
                log.debug("权重选择实例: {}:{} (weight: {})", instance.getHost(), instance.getPort(), weight);
                return instance;
            }
        }
        
        // 兜底返回最后一个实例
        return instances.get(instances.size() - 1);
    }
    
    /**
     * 最少连接负载均衡（基于实例权重）
     * 
     * @param instances 服务实例列表
     * @return 选中的实例
     */
    public ServiceInstance leastConnectionsChoose(List<ServiceInstance> instances) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        // 选择权重最高的实例（假设权重高表示连接数少）
        ServiceInstance selectedInstance = instances.get(0);
        double maxWeight = 0;
        
        for (ServiceInstance instance : instances) {
            String weightStr = instance.getMetadata().get("nacos.weight");
            double weight = weightStr != null ? Double.parseDouble(weightStr) : 1.0;
            
            if (weight > maxWeight) {
                maxWeight = weight;
                selectedInstance = instance;
            }
        }
        
        log.debug("最少连接选择实例: {}:{} (weight: {})", 
                selectedInstance.getHost(), selectedInstance.getPort(), maxWeight);
        return selectedInstance;
    }
    
    /**
     * 基于版本的负载均衡
     * 
     * @param instances 服务实例列表
     * @param preferredVersion 首选版本
     * @return 选中的实例
     */
    public ServiceInstance versionBasedChoose(List<ServiceInstance> instances, String preferredVersion) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        // 优先选择指定版本的实例
        List<ServiceInstance> preferredInstances = instances.stream()
                .filter(instance -> preferredVersion.equals(instance.getMetadata().get("version")))
                .toList();
        
        if (!preferredInstances.isEmpty()) {
            ServiceInstance instance = randomChoose(preferredInstances);
            log.debug("版本选择实例: {}:{} (version: {})", instance.getHost(), instance.getPort(), preferredVersion);
            return instance;
        }
        
        // 如果没有指定版本的实例，随机选择一个
        return randomChoose(instances);
    }
    
    /**
     * 基于区域的负载均衡
     * 
     * @param instances 服务实例列表
     * @param preferredRegion 首选区域
     * @return 选中的实例
     */
    public ServiceInstance regionBasedChoose(List<ServiceInstance> instances, String preferredRegion) {
        if (instances == null || instances.isEmpty()) {
            return null;
        }
        
        // 优先选择指定区域的实例
        List<ServiceInstance> preferredInstances = instances.stream()
                .filter(instance -> preferredRegion.equals(instance.getMetadata().get("region")))
                .toList();
        
        if (!preferredInstances.isEmpty()) {
            ServiceInstance instance = randomChoose(preferredInstances);
            log.debug("区域选择实例: {}:{} (region: {})", instance.getHost(), instance.getPort(), preferredRegion);
            return instance;
        }
        
        // 如果没有指定区域的实例，随机选择一个
        return randomChoose(instances);
    }
    
    /**
     * 使用Spring Cloud LoadBalancer执行请求
     * 
     * @param serviceId 服务ID
     * @param request 请求
     * @param <T> 返回类型
     * @return 请求结果
     */
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) {
        try {
            return loadBalancerClient.execute(serviceId, request);
        } catch (Exception e) {
            log.error("执行负载均衡请求失败: {}", serviceId, e);
            throw new RuntimeException("负载均衡请求执行失败", e);
        }
    }
    
    /**
     * 使用Spring Cloud LoadBalancer执行请求（指定URI）
     * 
     * @param serviceId 服务ID
     * @param originalUri 原始URI
     * @param request 请求
     * @param <T> 返回类型
     * @return 请求结果
     */
    public <T> T execute(String serviceId, URI originalUri, LoadBalancerRequest<T> request) {
        try {
            return loadBalancerClient.execute(serviceId, request);
        } catch (Exception e) {
            log.error("执行负载均衡请求失败: {} -> {}", serviceId, originalUri, e);
            throw new RuntimeException("负载均衡请求执行失败", e);
        }
    }
}
